
#ifndef __MLS_MESHDEFORMERVS_H_GL_
#define __MLS_MESHDEFORMERVS_H_GL_

#include "../glslKernel.h"
#include "../core/mlsDeformer.h"

class MlsMeshDeformerVS : public MlsDeformer<TConstraints<Point3> > {
   
   typedef TConstraints<Point3>     PConstraints;
public:
   ~MlsMeshDeformerVS() {}
   
   MlsMeshDeformerVS()
      :MlsDeformer<PConstraints>::MlsDeformer() {
      this->coSource = 0;
      this->coTarget = 0;
   }
   
   /// 
   /// @param m the mesh model
   /// @param constraints the initial constraints
   MlsMeshDeformerVS(const PConstraints &constraints)
      :MlsDeformer<PConstraints>::MlsDeformer(){
      
      /// GPU: vertex shader
      glActiveTexture(GL_TEXTURE1);
      glGenTextures(1, &texP);
      glBindTexture(GL_TEXTURE_RECTANGLE_NV, texP);
      glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_FLOAT_RGB32_NV, 1, constraints.size(), 0, 
                   GL_RGB, GL_FLOAT, &constraints.positions[0]);
      
      glActiveTexture(GL_TEXTURE2);
      glGenTextures(1, &texQ);
      glBindTexture(GL_TEXTURE_RECTANGLE_NV, texQ);
      glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_FLOAT_RGB32_NV, 1, constraints.size(), 0, 
                   GL_RGB, GL_FLOAT, &constraints.positions[0]);
      
      /// insert the number of control points into the source shader
      ostringstream oscpNumber;
      oscpNumber<<constraints.size();
      string firstline;
      firstline = "#define NCTRLPOINTS " + oscpNumber.str() + " \n";
      string shaderFileName = "mlsrigid.vs";
      ofstream fileout(shaderFileName.c_str(), ios::in | ios::out | ios::binary);
      assert(fileout);
      fileout.seekp(0, ios::beg);
      fileout<<firstline;
      fileout.close();
      
      mlsvs.vertex_source(shaderFileName.c_str());
      mlsvs.fragment_source("phong.fs");
      mlsvs.install(true);
      mlsvs.use();
      mlsvs.set_uniform("P", 1);
      mlsvs.set_uniform("Q", 2);
      mlsvs.use(false);
   }
   
   virtual void execute(const PConstraints &constraints) {
      
      glActiveTexture(GL_TEXTURE2);
      glBindTexture(GL_TEXTURE_RECTANGLE_NV, texQ);
      glTexSubImage2D(GL_TEXTURE_RECTANGLE_NV,0,0,0,1,constraints.size(),
                      GL_RGB,GL_FLOAT,&constraints.positions[0]);
      mlsvs.use();
      mlsvs.set_uniform("Q", 2);
      mlsvs.use(false);
   }
   
   void use(bool flag=true) { 
      mlsvs.use(flag);
   }
   
protected:
   
   glslKernel        mlsvs; // the shader
   GLuint            texP;  // texture id
   GLuint            texQ;  // texture id
};

#endif
